#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include "hash_table.h"

using namespace std;
using namespace msl;

extern char FIRST_NAMES[13][30];
extern char LAST_NAMES[13][30];
extern char FATHER_NAMES[13][30];

struct Purchase {
    int id;
    struct {
        string first_name;
        string last_name;
        string father_name;
    } full_name;
    string invoice;
    int count;
};

int main() {
    HashTableMap<string, Purchase> htm;
    map<int, string> ids;

    cout << "Menu of table:\n"
            "1) print - print table\n"
            "2) generate NUMBER - generate NUMBER records in table. Old ones are destroying\n"
            "3) add ID NAME SURNAME FATHERNAME INVOICE COUNT - add new record and print its number\n"
            "4) get ID|KEY - get record by ID or KEY\n"
            "5) delete ID|KEY - delete record by ID or KEY\n"
            "6) cls - clear screen\n";

    for(;;) {
        string line, cmd;
        getline(cin, line);
        istringstream iss(line);
        iss >> cmd;

        if(cmd == string("print")) {
            vector<Purchase> purs = htm.get_all();
            for(auto el: purs) {
                cout    << "+ " << el.id << " " << el.full_name.first_name << " " << el.full_name.last_name
                     << " " << el.full_name.father_name << " " << el.invoice << " " << el.count << "\n";
            }
            cout << "\n===================================\n";
            cout    << "\nElement count: " << htm.size() << "\n"
                 << "Collision count: " << htm.collision_count() << "\n";
        }

        else if(cmd == string("generate")) {
            htm = HashTableMap<string, Purchase>();
            ids = map<int, string>();
            int el_count; iss >> el_count;
            srand(time(NULL));
            for(int i=0; i<el_count; i++) {
                int finr =      rand() % 13; // sizeof(FIRST_NAMES);
                int lanr =      rand() % 13; // sizeof(LAST_NAMES);
                int fanr =      rand() % 13; // sizeof(FATHER_NAMES);
                int invr =      rand() % 1000000;
                int countr =    rand() % 1000000;

                Purchase p = {  i, {FIRST_NAMES[finr], LAST_NAMES[lanr], FATHER_NAMES[fanr]},
                              string("#") + to_string(invr), countr };
                htm.insert(p.invoice, p);
                ids.insert({i, p.invoice});
            }
        }

        else if(cmd == string("add")) {
            Purchase p;
            iss >> p.id >> p.full_name.first_name >> p.full_name.last_name
                >> p.full_name.father_name >> p.invoice >> p.count;
            if(p.invoice[0] != '#') {
                cout << "Invoice must have # symbol in first position\n";
            }
            else {
                htm.insert(p.invoice, p);
                ids.insert({p.id, p.invoice});
            }
        }

        else if(cmd == string("get")) {
            Purchase p;
            string sth; iss >> sth;
            int id = 0; string key;
            bool is_id = true;
            try { id = stoi(sth); }
            catch(exception &e) { is_id = false; }
            if(is_id) key = ids[id];
            try {
                p = htm.find(key);
                cout    << "= " << p.id << " " << p.full_name.first_name << " " << p.full_name.last_name
                     << " " << p.full_name.father_name << " " << p.invoice << " " << p.count << "\n";
            }
            catch(exception &e) {
                cout << "No found element by this ID (or KEY)\n";
            }
        }

        else if(cmd == string("delete")) {
            string sth; iss >> sth;
            int id = 0; string key;
            bool is_id = true;
            try { id = stoi(sth); }
            catch(exception &e) { is_id = false; }
            try {
                if(is_id) {
                    key = ids.at(id);
                    ids.erase(ids.find(id));
                }
                bool res = htm.erase(key);
                if(res) cout << "Element has deleted\n";
            }
            catch(exception &e) {
                cout << "No found element by this ID (or KEY)\n";
            }
        }

        else if(cmd == string("cls")) {
#if defined(_WIN32)
            system("cls");
#elif defined(__linux__)
            system("clear");
#else
#error System does not support
#endif

            cout << "Menu of table:\n"
                    "1) print - print table\n"
                    "2) generate NUMBER - generate NUMBER records in table. Old ones are destroying\n"
                    "3) add ID NAME SURNAME FATHERNAME INVOICE COUNT - add new record and print its number\n"
                    "4) get ID|KEY - get record by ID or KEY\n"
                    "5) delete ID|KEY - delete record by ID or KEY\n"
                    "6) cls - clear screen\n";
        }

        else if(cmd == string("quit")) {
            return 0;
        }

        else {
            cout << "There is no command.\n";
        }
    }
}
